using System;
using System.Collections;
using System.Collections.Generic;
using JufGame.AI;
using JufGame.Collections.Generic;
using UnityEngine;

namespace JufGame
{
	public class OctreeNode: IAStarNode<OctreeNode>, IComparable<OctreeNode>
	{
		public int HeapIndex { get; set; }
        public float SelfCost { get; set; }
        public float GCost { get; set; }
        public float HCost { get; set; }
		public float FCost => GCost + HCost;
        public OctreeNode Parent{ get; set; }
        public List<OctreeNode> Children;
		public readonly Bounds NodeBounds;
		public readonly List<Collider> ContainedObjects;

		public OctreeNode(Bounds bounds, OctreeNode parent)
		{
			NodeBounds = bounds;
			Parent = parent;
			ContainedObjects = new List<Collider>();
			SelfCost = 1;
		}
		public void AddObject(GameObject gameObject, float stopSize)
		{
			DivideAndAdd(gameObject.GetComponent<Collider>(), stopSize);
		}
		private void DivideAndAdd(Collider collider, float stopSize)
		{
			if (NodeBounds.size.y <= stopSize)
			{
				ContainedObjects.Add(collider);
				return;
			}
			Children ??= new List<OctreeNode>(8);
			var isDivided = false;
			var step = NodeBounds.size.y / 4;
			Vector3 offset;
			for (int i = 0; i < 8; ++i)
			{
				if(Children.Count < 8) //子列表为空，初始化各子节点
				{
					//0~7的二进制位结构恰好满足我们所需要的组合形式
					offset.x = (1 & i) != 0 ? step : -step;
					offset.y = (2 & i) != 0 ? step : -step;
					offset.z = (4 & i) != 0 ? step : -step;
					var childBounds = new Bounds(NodeBounds.center + offset, 2 * step * Vector3.one);
					Children.Add(new OctreeNode(childBounds, this));
				}
				if (Children[i].NodeBounds.Intersects(collider.bounds)) //有碰撞的节点进一步划分
				{
					isDivided = true;
					Children[i].DivideAndAdd(collider, stopSize);
				}
			}
			if(!isDivided)//当前碰撞节点不可进一步划分时
			{
				ContainedObjects.Add(collider);
				Children = null;
			}
		}
		public void Draw()
		{
			if(ContainedObjects.Count == 0) //绘制无物体占据的节点
			{
				Gizmos.color = Color.green;
				Gizmos.DrawWireCube(NodeBounds.center, NodeBounds.size);
			} 
			else 
			{
				Gizmos.color = new Color(0, 0, 1, 0.3f);
				Gizmos.DrawCube(NodeBounds.center, NodeBounds.size);
			}
			Gizmos.color = Color.red;
			foreach(var obj in ContainedObjects)
			{
				Gizmos.DrawWireCube(obj.bounds.center, obj.bounds.size);
			}
			if(Children != null)
			{
				for (int i = 0; i < Children.Count; ++i)
				{
					Children[i]?.Draw();
				}
			}
		}

        public float GetDistance(OctreeNode otherNode)
        {
			return Vector3.Distance(NodeBounds.center, otherNode.NodeBounds.center);
        }

        public List<OctreeNode> GetSuccessors(object nodeMap)
        {
			var map = (MyGraph<OctreeNode, int>)nodeMap;
			return map.GetNeighbor(this);
		}

        public int CompareTo(OctreeNode other)
        {
        	float res = FCost - other.FCost;
			if(res == 0)
				res = HCost - other.HCost;
			return (int)res;
        }
    }
}
